﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		TagCloud.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Dexter.Services;

namespace Dexter.Web.Controls {
	public class TagCloud {
		readonly Collection <RangeGroup> ranges = new Collection <RangeGroup> ( );
		readonly IUrlBuilder urlBuilder;

		string[] className = new[] {
			"CommonTag7" , "CommonTag6" , "CommonTag5" , "CommonTag4" , "CommonTag3" , "CommonTag1" , "CommonTag1"
		};

		List <TagInfo> dataSource = new List <TagInfo> ( );
		double scale;

		public TagCloud ( List <TagInfo> tags , IUrlBuilder urlBuilder ) {
			dataSource = tags;
			this.urlBuilder = urlBuilder;
		}

		public string UnorderedListClassName { get; set; }

		public string[] ClassName {
			get { return className; }
			set { className = value; }
		}

		internal List <TagInfo> DataSource {
			get { return dataSource; }
			set { dataSource = value; }
		}

		string GetTagCloudCssClass ( TagInfo tag ) {
			if ( ranges.Count == 0 ) {
				return string.Empty;
			}

			foreach ( RangeGroup t in ranges ) {
				if ( ( tag.CalculatedCount >= t.From ) && ( tag.CalculatedCount <= t.To ) ) {
					return t.CssClass;
				}
			}

			return ranges[ ranges.Count - 1 ].CssClass;
		}

		void CalculateRange ( bool alfabeticSort ) {
			if ( ( dataSource.Count > 0 ) && ( className.Length > 0 ) ) {
				dataSource.Sort ( new TagComparer ( SortByEnum.Count ) );

				scale = ( dataSource.Count - 1 ) / ( double ) className.Length;

				for ( int i = 0; i < className.Length; i++ ) {
					ranges.Add ( new RangeGroup ( dataSource[ ( int ) ( scale * i ) ].CalculatedCount , dataSource[ ( int ) ( scale * ( i + 1 ) ) ].CalculatedCount , className[ i ] ) );
				}

				if ( alfabeticSort ) {
					dataSource.Sort ( new TagComparer ( SortByEnum.Name ) );
				}
			}
		}

		public string ToString ( bool alfabeticSort ) {
			if ( DataSource.Count < 1 ) {
				return string.Empty;
			}

			CalculateRange ( alfabeticSort );

			StringBuilder builder = new StringBuilder ( );

			if (!string.IsNullOrEmpty ( UnorderedListClassName ))
				builder.AppendFormat ( "<ul class=\"{0}\">\r\n", UnorderedListClassName );
			else
				builder.Append ( "<ul>\r\n" );

			if ( !alfabeticSort ) {
				for ( int i = dataSource.Count - 1; i > -1; i-- ) {
					string url = string.IsNullOrEmpty ( dataSource[ i ].Url )
					             	? urlBuilder.Tag.Detail ( dataSource[ i ].Name )
					             	: dataSource[ i ].Url.EncodeUrl ( );
					builder.AppendFormat ( "<li class=\"{0}\"><a title=\"{2} ({3})\" href=\"{1}\" rel=\"tag\">{2}</a></li>\r\n" , GetTagCloudCssClass ( dataSource[ i ] ) , url.ToLower ( ) , dataSource[ i ].Name.EncodeHtml ( ) , dataSource[ i ].Count );
				}
			}
			else {
				foreach ( TagInfo t in dataSource ) {
					string url = string.IsNullOrEmpty ( t.Url )
					             	? urlBuilder.Tag.Detail ( t.Name )
					             	: t.Url.EncodeUrl ( );
					builder.AppendFormat ( "<li class=\"{0}\"><a title=\"{2} ({3})\" href=\"{1}\" rel=\"tag\">{2}</a></li>\r\n" , GetTagCloudCssClass ( t ) , url.ToLower ( ) , t.Name.EncodeHtml ( ) , t.Count );
				}
			}

			builder.Append ( "</ul>" );

			return builder.ToString ( );
		}

		public override string ToString ( ) {
			return ToString ( true );
		}
	}

	internal enum SortByEnum {
		Name = 0 ,
		Count = 1
	}

	[Serializable]
	public class TagInfo {
		readonly int weight = 1;

		public TagInfo ( ) {}

		public TagInfo ( string name , int count , int weight ) {
			Name = name;
			Count = count;
			this.weight = weight;
			Url = string.Empty;
		}

		public TagInfo ( string name , int count , int weight , string url ) {
			Name = name;
			Count = count;
			this.weight = weight;
			Url = url;
		}

		public int Count { get; set; }
		public string Name { get; set; }

		public int CalculatedCount {
			get { return Count * weight; }
		}

		public string Url { get; set; }
	}

	internal class RangeGroup {
		public string CssClass;
		public int From;
		public int To;

		public RangeGroup ( int from , int to , string cssClass ) {
			From = from;
			To = to;
			CssClass = cssClass;
		}
	}

	internal class NumeriComparer : Comparer <int> {
		public override int Compare ( int x , int y ) {
			if ( x > y ) {
				return 1;
			}

			if ( x < y ) {
				return -1;
			}

			return 0;
		}
	}

	internal class TagComparer : IComparer <TagInfo> {
		readonly SortByEnum sortBy = SortByEnum.Name;

		public TagComparer ( SortByEnum sortBy ) {
			this.sortBy = sortBy;
		}

		#region IComparer<TagInfo> Members

		public int Compare ( TagInfo x , TagInfo y ) {
			if ( x != null ) {
				if ( x.CalculatedCount <= 0 ) {
					x.Name = x.Name.Replace ( "\r\n" , " " );
				}
			}

			if ( y != null ) {
				if ( y.CalculatedCount <= 0 ) {
					y.Name = y.Name.Replace ( "\r\n" , " " );
				}
			}

			if ( x == null && y == null ) {
				return 0;
			}

			if ( x == null ) {
				return -1;
			}

			if ( y == null ) {
				return 1;
			}

			if ( sortBy == SortByEnum.Name ) {
				return ( ( new CaseInsensitiveComparer ( ) ).Compare ( x.Name , y.Name ) );
			}

			return ( new NumeriComparer ( ).Compare ( x.CalculatedCount , y.CalculatedCount ) );
		}

		#endregion
	}
}
